* 68000 assembly language program * ------------------------------- * * Priciples of Computers2 ICA * * To emulate a simple 4 function calculator including * the functions +,-,/,* * The program must handle integers in the range 0-999. * * ----------------------------------------------------------------------- ORG $400 ;Store program from location 400h BSR john ;version begin BSR erase ;clean all storage space in memory BSR messg ;show the startup message BSR clean ;clean up all scratch space areas BSR input1 ;get the first sequence of no.s BSR saven1 ;save the sequence as number CMP #1,D5 ;was the last char an integer? BNE sopsub ;if not then branch and save the char(poss an 'op') BSR clean ;clean up all scratch space areas BSR chget ;get a single char from the std/io BSR store ;save the char BSR getop ;now see if the char was indeed an operator sopsub BSR saveop ;if it was, then save it in memory('op') CMP #1,D6 ;if this is set, then there was an error BEQ begin ;if another integer was input, then error - restart BSR clean ;clean up all scratch space areas BSR input1 ;get the second sequence of integers BSR saven2 ;save the sequence as number2 CMP #6,D5 ;was the last char an equals? BEQ final ;if yes, then goto final processing BSR clean ;else clean up all scratch space areas BSR getequ ;and now get the equals char BSR clean ;clean up all scratch space areas final BSR do_opp ;performs the calculation CMP #1,D5 ;did the divide 'op' print out its result? BEQ cleanup ;if yes, then skip to the prompt BSR clean ;cleanup BSR output ;else output result cleanup BSR clean ;cleanup BSR newline ;insert a blank line - prettiness only BSR goagain ;do we want to go again? CMP #$20,D1 ;if space is pressed, then yes. BEQ begin ;now back to beginning of code exit STOP #$2700 ;else stop the program ORG $1000 ;Start storing data at location 1000h valid CMP #llimit,D4 ;Compare temp area with lower limit(0) BLT bex ;If less than 0 then go to 'bex' (before 'ex') CMP #ulimit,D4 ;Compare temp area with upper limit(9) BGT bex ;If greater than 9 then go to 'bex' (before 'ex') MOVE.B #1,D5 ;Set D5 to 1 - ie, number is between 0-9 BRA ex ;Branch to 'ex' and therefore miss clearing D5 bex BRA getop ;if its not a 'int' - is it an 'op' ex RTS ;Return to place from where called input1 ADDQ #1,D2 ;start a counter - use quick add BSR chget ;get a single char BSR store ;store char in d4 BSR valid ;is d4-char valid? CMP #1,D5 ;is d5 = 1? BNE endinpb ;if not then exit bsrch BSR change ;change char to integer CMP #0,D7 ;is anything in d7? BEQ firstad ;if not then goto firstadd add_mul MOVE.B #0,D5 ;clear d5 MOVE.B D7,D3 ;make a copy of D7 in D3. MULU #10,D3 ;multiply copy by 10 CMP #max,D3 ;is copy >= 1000? BGE add_ext ;if yes then exit MULU #10,D7 ;else multiply D7 by 10 ADD.W D4,D7 ;now add D5 to D7. MOVE.B #1,D5 ;set d5 to 1 add_ext CMP #1,D5 ;was addmul successful? BNE endinpb ;if not then end input routine BRA endinpa ;else goto end of loop firstad MOVE.B D4,D7 ;move D4 to D7 CMP #3,D2 ;is the count up to 3 yet? BEQ endinpb ;if yes then exit endinpa BRA input1 ;back to beginning of loop endinpb RTS getop CMP #43,D4 ;is the char a '+'? BEQ ad ;yes CMP #45,D4 ;no; is the char a '-'? BEQ min ;yes CMP #47,D4 ;no; is the char a '/'? BEQ divi ;yes CMP #42,D4 ;no; is the char a '*'? BEQ mult ;yes CMP #$3D,D4 ;no; is it a '='? BEQ equ ;yes CMP #$D,D4 ;treat return as '=' BEQ equ ;If so, then branch to equals routine CMP #bhelp,D4 ;was the HELP key pressed? BEQ helpdsp ;if so, then display help CMP #lhelp,D4 ;was the help key pressed? BEQ helpdsp ;if so, then display help CMP #bcred,D4 ;was the CREDITS key pressed? BEQ credits ;if so, then display credits CMP #lcred,D4 ;was the credits key pressed? BEQ credits ;if so, then display credits MOVE.B #0,D5 ;set D5 to 1 if no 'op' (eg 'int') BSR newline ;- char was neither an 'int' nor an BSR oedisp ;- and 'op' so output an error message BSR display ;- BSR newline ;- BRA op_ex ;now exit the subprogram equ MOVE.B #6,D5 ;set the level of d5 to 6 BRA op_ex ;exit subprogram mult MOVE.B #2,D5 ;set the level of d5 to 2 BRA op_ex ;exit subprogram divi MOVE.B #3,D5 ;set the level of d5 to 3 BRA op_ex ;exit subprogram min MOVE.B #4,D5 ;set the level of d5 to 4 BRA op_ex ;exit subprogram ad MOVE.B #5,D5 ;set the level of d5 to 5 op_ex RTS ;exit subprogram do_opp MOVE.B op,D5 ;move the 'op' level to D5 CMP #2,D5 ;- find out what 'level' D5 is at, and BEQ op_mult ;- then branch to the particular CMP #5,D5 ;- subprogram that corresponds to that BEQ op_add ;- operation. eg level '3' = divide CMP #3,D5 ;- BEQ op_div ;- CMP #4,D5 ;- BEQ op_min ;- CMP #1,D5 ;level 1 or below is not an operator so BLE errout ;print out an error message. ds_exit RTS ;exit subprogram op_mult MOVE.W number2,D7 ;- This is a simple routine for MOVE.W number1,D6 ;- multiplying two 16bit integers, the MULS.W D6,D7 ;- 32bit result is in D7, and is stored MOVE.L D7,result ;- in memory as 'result' RTS ;exit subprogram setof MOVE.B #1,overflow RTS op_div BSR clean ;make sure all the scratch areas are clear MOVE.W number2,D7 ;number2 MOVE.W number1,D4 ;make a copy of number 1 in D4 MOVE.W number1,D6 ;number1 CMP D6,D7 ;is number2 bigger than number1 BGT noloops ;if yes then exit subloop ADDQ #1,D2 ;add 1 to division count SUB.W D7,D4 ;subtract number2 from D4 CMP D7,D4 ;is remainder > original? BLT endloop ;if yes then exit BRA subloop ;and go back to subloop noloops MOVE.L #0,result ;set result to 0 (its less than 1) BSR divdisp ;call the 'less than 1' message BSR display ;display the message BSR newline ;put in another newline. MOVE.B #1,D5 ;we will need this to we have displayed lessthan1 BRA enddiv endloop MOVE.L D2,result ;move the number of loops to result enddiv RTS ;the number of loops is number1/number2 op_min MOVE.W number1,D7 ;- This subprogram takes number1 and MOVE.W number2,D6 ;- number2 and performs a subtraction CMP.W D7,D6 ;compare number1 and number2 BGE subtr ;is number2 larger? MOVE.W number1,D6 ;if yes then swap MOVE.W number2,D7 ; MOVE.B #1,flag ;set negative flag to true subtra SUB.W D6,D7 ;perform subtraction MOVE.L D7,result ;store result in memory RTS ;exit subprogram op_add MOVE.W number2,D7 ;- This routine performs an addition MOVE.W number1,D6 ;- operation on the two numbers, and ADD.W D6,D7 ;- then places the new number in result MOVE.L D7,result ;- RTS ;exit subprogram store MOVE.B D1,D4 ;store d1 in d4 RTS change SUB #48,D4 ;subtract 48 from ascii value of d4 RTS getequ BSR chget ;get a char from the std/io BSR store ;store in D4 BSR valid ;is the char valid? CMP #0,D5 ;0 signifies not valid BEQ equ_ext ;branch to exit BRA getequ ;back to start of loop equ_ext RTS ;exit subprogram clean CLR.L D0 ;- This subprogram cleans up all CLR.L D1 ;- scratch space areas CLR.L D2 ;- CLR.L D3 ;- CLR.L D4 ;- CLR.L D5 ;- CLR.L D6 ;- CLR.L D7 ;- RTS erase MOVE.L #0,result ;- Reset all memory locations which MOVE.W #0,number1 ;- are used to hold data for MOVE.W #0,number2 ;- calculations MOVE.B #0,flag ;- MOVE.B #0,op ;- RTS chget MOVE.B #5,D0 ;Gets a character from the keyboard TRAP #15 ;stores the ascii value in D1 RTS ;Back to the routine from where it was called. chput MOVE.B #6,D0 ;Gets a character from D1, and outputs TRAP #15 ;it to the screen RTS ;Back to the routine from where it was called. newlin MOVE.B #$D,D1 ;Put the newline character in D1 BSR chput ;Output D1 to the screen RTS saven1 MOVE.W D7,number1 ;save result of processing in 'number1' RTS ;exit subprogram saven2 MOVE.W D7,number2 ;save result of processing in 'number2' RTS ;exit subprogram saveop CMP #43,D4 ;is the char a '+'? BEQ save ;then save CMP #45,D4 ;is the char a '-'? BEQ save ;then save CMP #47,D4 ;is the char a '/'? BEQ save ;then save CMP #42,D4 ;is the char a '*'? BEQ save ;then save BSR newline ;put in a newline BSR nedisp ;if not a 'op' then you've tried to go over 999 BSR display ;display the numerical error message. BSR newline ;put in a newline BSR rsdisp ;ask to re-input data BSR display ;display the message MOVE.B #1,D6 ;set d6 BRA endsave ;end the save routine save MOVE.B D5,op ;save the level of the operator in 'op' endsave RTS ;exit subprogram stord7 MOVE.L D7,D6 ;make a copy of result RTS negoutp MOVE.B #'-',D1 ;put a '-' in the output stream BSR chput ;call the single ch display routine RTS output BSR clean ;clean up all scratch areas MOVE.B #6,D2 ;set the count to 6(places) MOVE.L result,D7 ;copy result into a register MOVE.L result,D5 ;a copy in d5 for reference MOVE.W #maxmult,D4 ;make a copy of highest 16bit integer in D4 CMP.L D4,D7 ;did a multiplication result in a >16bit result? BLE loopstka ;if not, then goto loop BSR ofsub ;put pointer to error in A0 BSR display ;display error message BRA exoutp ;exit subprogram loopstka CMP #1,flag ;is negative flag set? BEQ negoutp ;yes then output '-' loopstk CMP #0,D2 ;is count = 0? BEQ exloop ;if yes, then exit loop * MOVE.L D6,D7 ;- These are 68020 instructions....pity, they * DIVSL.L #10,D7:D6 ;- would have let me use 999*999 :-( DIVU #10,D7 ;divide the result by 10 - gets lsb SWAP D7 ;swap remainder and whole number words around MOVE.B D7,-(SP) ;store integer on the stack (f.i.l.o) SWAP D7 ;get the whole number back AND.L #$0000FFFF,D7 ;get rid of the remainder SUB #1,D2 ;decrement the loop counter BRA loopstk ;back to loop exloop MOVE.B #6,D2 ;set up the counter again loopout CMP #0,D2 ;is counter = 0? BEQ exoutp ;if yes, then exit MOVE.B (SP)+,D1 ;get integer from stack, and increment stack pointer SUB #1,D2 ;decrement the counter CMP #0,D1 ;is the number a zero? BNE setflag ;if not, then set the print flag backher CMP #1,D3 ;is print flag set? BEQ addline ;if yes then continue BRA loopout ;else back to loop addline ADD.B #$30,D1 ;re-encode the integer as an ascii char CMP #1,D3 ;is the flag set? BNE loopout ;if not then back to loop MOVE.B #6,D0 ;- else get a char from D1, and outputs TRAP #15 ;- it to the screen BRA loopout ;back to the loop zeroout MOVE.B #$30,D1 ;if result is a zero - simply output a zero BSR chput ;ouput single char BRA exoutp ;goto exit setflag MOVE.B #1,D3 ;if the number is non-zero, then set the display flag BRA backher ;go back to place from where called exoutp RTS ;exit subprogram display MOVE.B (A0)+,D1 ;- This is a generic display function. CMP.B #'@',D1 ;- A pointer to the text string is placed BEQ dis_ext ;- on A0 and the string traversed (A0)+ BSR chput ;- , copied to D1 and ouput by the 'chput' BRA display ;- routine. dis_ext RTS ;exit subprogram messg BSR newline ;- This section of code displays the LEA messg1,A0 ;- program banner that is shown when- BSR display ;- -ever the user is prompted to input BSR newline ;- a new sum. LEA messg3,A0 ;- The generic display routine is called BSR display ;- to output the string pointed at by A0. BSR newline ;- RTS ;exit subprogram goagain BSR newline ;- A simple subprogram to display a LEA again,A0 ;- message asking whether the user BSR display ;- would like to continue or not. BSR newline ;- The test is in the main body. BSR chget ;- RTS ;exit subprogram space LEA addspc,A0 ;adds a space to the output if needed. RTS ;exit subprogram newline MOVE.B #$0A,D1 ;- A new line is inserted and the BSR chput ;- cursor returned to the start of the MOVE.B #$0D,D1 ;- new line with this code - used mainly BSR chput ;- for tidiness of output. RTS ;exit subprogram nedisp LEA numerr,A0 ;pointer for numerr placed on A0 RTS ;exit subprogram oedisp LEA operr,A0 ;pointer for operr placed on A0 RTS ;exit subprogram rsdisp LEA restart,A0 ;pointer to restart message placed on A0 RTS ;exit subprogram errout BSR oedisp ;- a combination of operror and the BSR display ;- display function, used in do_opp. RTS ;exit subprogram divdisp LEA diverr,A0 ;a message when divide result is < 1 RTS ;exit subprogram helpdsp BSR newline ;- This rather large subprogram calls in LEA help1,A0 ;- turn the display routine on several, BSR display ;- large test strings in memory. BSR newline ;- These strings contain some useful info LEA help2,A0 ;- about the program and its functions... BSR display ;- This help text is called by pressing BSR newline ;- the 'h' key while the program is LEA help3,A0 ;- running. BSR display BSR newline LEA help4,A0 BSR display BSR newline LEA help5,A0 BSR display BSR newline LEA help6,A0 BSR display BSR newline LEA help2,A0 BSR display BSR newline LEA help7,A0 BSR display BSR newline LEA help8,A0 BSR display BSR newline LEA help9,A0 BSR display BSR newline LEA help2,A0 BSR display BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline BSR newline RTS ;exit subprogram credits BSR newline ;- This subprogram just shows some nice LEA help19,A0 ;- details and sources of information BSR display ;- that I used. BSR newline LEA help2,A0 BSR display BSR newline LEA help10,A0 BSR display BSR newline LEA help11,A0 BSR display BSR newline LEA help12,A0 BSR display BSR newline LEA help13,A0 BSR display BSR newline LEA help14,A0 BSR display BSR newline BSR newline LEA help15,A0 BSR display BSR newline LEA help16,A0 BSR display BSR newline LEA help17,A0 BSR display BSR newline LEA help18,A0 BSR display BSR newline BSR newline LEA help21,A0 BSR display BSR newline LEA help22,A0 BSR display BSR newline LEA help23,A0 BSR display BSR newline LEA help24,A0 BSR display BSR newline LEA help2,A0 BSR display BSR newline BSR newline BSR newline BSR newline BSR newline RTS john LEA johntxt,A0 ;- Prints out the program title BSR display ;- and current version. BSR newline ;a newline for tidiness RTS ;exit subprogram ofsub LEA ofmessg,A0 RTS ******************************************************** * Define some constants * llimit EQU 48 ;The lower limit for an ascii char is x ulimit EQU 57 ;The upper limit for an ascii char is y max EQU 1000 ;when we should stop adding. return EQU $D ;ascii value of return ' '. equal EQU $3D ;ascii value of equals '='. bhelp EQU $48 ;ascii value of 'H' lhelp EQU $68 ;ascii value of 'h' bcred EQU $43 ;ascii value of 'C' lcred EQU $63 ;ascii value of 'c' zero EQU 0 ; int EQU 1 ; maxmult EQU 65535 ;max result for 16bit integer maxres EQU 998001 ;999x999 halfand EQU %00000000000000001111111111111111 * ******************************************************** * This is what the value of d5 represents * integer EQU 1 multi EQU 2 divide EQU 3 minus EQU 4 adding EQU 5 equals EQU 6 none EQU 0 * ******************************************************** * A help banner * help1 DC.B ' Calculator help text v1.1 @',0 help2 DC.B ' --------------------------------------------------- @',0 help3 DC.B ' This program simulates a simple 4 function numeric calculator.@',0 help4 DC.B ' You are allowed to use integers up to and including 999, only basic functions@',0 help5 DC.B ' are implemented.@',0 help6 DC.B ' Operators allowed are plus(+), minus(-), multiplication(*) and division(/).@',0 help7 DC.B ' Limitations.@',0 help8 DC.B ' * Negatives are not supported.@',0 help9 DC.B ' * Division only gives integer values.@',0 help10 DC.B ' Development tools used.@',0 help11 DC.B ' * Teesside University 68K cross assembler@',0 help12 DC.B ' * Teesside University 68K simulator@',0 help13 DC.B ' * BSVC-2.0 68000 simulator studio (Linux)@',0 help14 DC.B ' * DOSemu v0.66.7 for iNTEL Linux@',0 help15 DC.B ' Enhancements over standard ICA.@',0 help16 DC.B ' * Extensive handling of input errors@',0 help17 DC.B ' * Results handled OVER 65535 (16bit)@',0 help18 DC.B ' * Non-output of overflowed results@',0 help19 DC.B ' Calculator credits and data text v1.0@',0 help20 DC.B ' * General improvement in user interface@',0 help21 DC.B ' Sources of information, and thanks.@',0 help22 DC.B ' * A.Clements 68000 Family assembly language@',0 help23 DC.B ' * A.Clements Microprocessor systems design@',0 help24 DC.B ' * B.W.Mott BSVC processor simulation famework@',0 * ******************************************************** * the startup string * johntxt DC.B ' Calculator program v980428c@',0 ;start up string * ******************************************************** * Have to figure out a way of displaying errors...hmmm.. * messg1 DC.B ' Please enter a calculation.@',0 ;the opening message messg2 DC.B ' (0-999, and using +,-,/,*)@',0 ;guide to symbols allowed messg3 DC.B ' -- H=help --- C=credits ---@',0 ;the helpline numerr DC.B ' Number must be 0-999!@',0 ;Outside of range, shouldnt be needed operr DC.B ' Invalid operator!@',0 ;Key other than +-*/ restart DC.B ' Please re-enter the sum. ->@',0 ;message when error occurs addspc DC.B ' @',0 ;to leave a space diverr DC.B ' Less than 1 @',0 ;when a divide will be less than 1 again DC.B ' Press to continue...@',0 ;prompt for the user ofmessg DC.B ' Error - Overflow!@',0 ;display this instead of result * * ******************************************************** * Now we set up all the areas of storage in memory... * number1 DS.W 1 ;Reserve 16 bits of storage for num1 number2 DS.W 1 ;Reserve 16 bits of storage for num2 op DS.B 1 ;Holds ascii val of operator temp8 DS.B 1 ;Reserve a byte for temp useage temp16 DS.W 1 ;Reserve a word for temp useage result DS.L 1 ;A long word (32bits) to hold results flag DS.B 1 ;whether its a -ive or not. overflow DS.B 1 ;shows whether the result of a '*' is over 16bits * * ********************************************************* * Description of some things. * * purpose of storage * * name - contents - d/size - description * * d1 - ascii - B - holds the character that is recieved from trap function. * d2 - integer - B - counter (counts to 3) * d3 - integer - B - used when testing whether result will be bigger than 999 * d4 - integer - B - holds the converted form of the ascii char. * d5 - boolean - B - tells whether character inputted is within range. * d6 - integer - W - hold contents of int1+int2+int3 before adding to temp. * * num1 - integer1 - W - holds upto a 3 digit integer. * num2 - integer2 - W - holds upto a 3 digit integer. * op - ascii - B - numerical operator is held here. * tmp8 - varies - B - a byte of scratch space. * tmp16- varies - W - a word of scratch space. * res - integer - L - final result stored here. * * ********************************************************* END $400